home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_09_08 / 9n08106a < prev    next >
Text File  |  1991-04-09  |  8KB  |  316 lines

  1. /*******************************************************
  2. *    plist.c:    Process Source Listings for Publication
  3. *                Written by Leor Zolman, 4/91
  4. *
  5. *    Usage:
  6. *            plist [-t#[,@]] [-n[#]] [-c#] [-o] <file(s)>
  7. *
  8. *  Options:
  9. *    -t#[,@]:    Set new tab spacing to every # columns
  10. *                    If @ given, specifies OLD tab spacing
  11. *                    (Both # and @ default to TAB_SETTING)
  12. *  -n[#]:        Generate line numbers, using # as field
  13. *                    width (defaults to NUM_WIDTH)
  14. *  -c#:            Right-justify comments to column #
  15. *  -o            Write output into ".lst" file(s)
  16. *                    If omitted, output goes to stdout.
  17. *  Compile:
  18. *        Turbo C:
  19. *            tcc plist.c [wildargs.obj]
  20. *        Xenix C:
  21. *            cc plist.c -o plist
  22. *****************************************************/
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28.  
  29. #define    XENIX        0    /* 1 for Xenix, 0 for DOS    */
  30. #define MAXLINE        200    /* longest allowable line    */
  31. #define TAB_SETTING 4    /* default soft tab setting */
  32. #define NUM_WIDTH    3    /* default line # width        */
  33. #define    TRUE        1
  34. #define    FALSE        0
  35.  
  36. char *makofname(char *, char *);
  37. void do_line(char *);
  38. void dofile(char *);
  39.  
  40. #if XENIX
  41.     char *strstr( char *,  char * );
  42. #endif
  43.  
  44. void pass1(char *, char *);
  45. void pass2(char *);
  46.  
  47. int docmnts = FALSE;    /* do comments                */
  48. int donums = FALSE;        /* line numbering flag        */
  49. int make_lst = FALSE;    /* create .LST files        */
  50. int numwidth = NUM_WIDTH;
  51. int tabstop = TAB_SETTING;
  52. int old_tab = TAB_SETTING;
  53. int cmnt_col;            /* col. to right-justify to */
  54.  
  55. char fmt[20];            /* line numbering fmt spec    */
  56. FILE *fpi, *fpo;        /* Input and output ptrs    */
  57. int lineno;                /* current line number        */
  58.  
  59. void main(argc, argv)
  60. int argc;
  61. char **argv;
  62. {
  63.     int i, j;
  64.                                 /* Process command line options: */
  65.     for (i = 1; i < argc; i++)
  66.         if (argv[i][0] == '-')
  67.         {
  68.             switch (tolower(argv[i][1]))
  69.             {
  70.                 case 'n':    donums = TRUE;
  71.                             if (j = atoi(&argv[i][2]))
  72.                                 numwidth = j;
  73.                             break;
  74.  
  75.                 case 't':    j = sscanf(&argv[i][2], "%d,%d",
  76.                                 &tabstop, &old_tab);
  77.                             break;
  78.  
  79.                 case 'c':    docmnts = TRUE;
  80.                             cmnt_col = atoi(&argv[i][2]);
  81.                             if (cmnt_col < 30)
  82.                                 fprintf(stderr, 
  83.                                     "WARNING: -c value small!\n");
  84.                             break;
  85.  
  86.                 case 'o':    make_lst = TRUE;
  87.                             break;
  88.  
  89.                 default:    fprintf(stderr, "Unknown option: '%s'\n",
  90.                                         argv[i]);
  91.                             exit(0);
  92.             }
  93.             for (j = i; j < argc - 1; j++)    /* compress */
  94.                 argv[j] = argv[j + 1];        /* arg list */
  95.             argc--;
  96.             i--;
  97.         }
  98.  
  99.     if (argc < 2)
  100.         exit(fprintf(stderr,
  101.             "Usage: plist [-t#] [-n[#]] files...\n"));
  102.  
  103.     if (donums)                /* create line number format string */
  104.         sprintf(fmt, "%%%dd: ", numwidth);
  105.  
  106.     for (i = 1; i < argc; i++)
  107.         dofile(argv[i]);    /* process list of given files        */
  108. }
  109.  
  110. /*
  111.  * Process the named file.
  112.  * If make_lst is true, create a .LST file for output.
  113.  * Otherwise, write output to standard output.
  114.  */
  115.  
  116. void dofile(fname)
  117. char *fname;
  118. {
  119.     char linbuf[MAXLINE];
  120.     char ofname[30];
  121.  
  122.     if ((fpi = fopen(fname, "r")) == NULL)
  123.     {
  124.         fprintf(stderr, 
  125.             "\aCan't open input file \"%s\"\n", fname);
  126.         return;
  127.     }
  128.  
  129.     if (make_lst)                    /* if making .LST files...    */
  130.     {
  131.         makofname(ofname, fname);    /* create output filename    */
  132.         if ((fpo = fopen(ofname, "w")) == NULL)
  133.         {
  134.             fprintf(stderr, "\aCan't create \"%s\"\n", ofname);
  135.             fclose(fpi);
  136.             return;
  137.         }
  138.         fprintf(stderr, "Creating %s...\n", ofname);
  139.     }
  140.     else                            /* write to standard output    */
  141.         fpo = stdout;
  142.  
  143.     for (lineno=1;
  144.         fgets(linbuf, MAXLINE, fpi); lineno++)
  145.                 do_line(linbuf);    /* process each line        */
  146.  
  147.     fclose(fpi);                    /* close input file            */
  148.     if (make_lst)                    /* and, if writing .LST,    */
  149.         fclose(fpo);                /*   then close that too    */
  150. }
  151.  
  152. /*
  153.  * do_line(): Process a line of text
  154.  */
  155.  
  156. void do_line(cp)
  157. char *cp;
  158. {
  159.     char result[MAXLINE], *resultp;
  160.  
  161.     resultp = result;
  162.     if (donums)                        /* if we're generating line nos. */
  163.     {
  164.         sprintf(result, fmt, lineno);
  165.         resultp += numwidth + 2;
  166.     }
  167.  
  168.     pass1(cp, resultp);                    /* perform tab translation    */
  169.     if (docmnts)
  170.         pass2(result);                    /* right justify comments    */
  171.  
  172.     fputs(result, fpo);                    /* write finished line        */
  173. }
  174.  
  175. /*
  176.  * Perform tab translation for the line pointed to by cp.
  177.  * Within comments, interpret soft tab as having spacing
  178.  * of ORIGINAL soft tab setting, not the new tab setting.
  179.  */
  180.  
  181. void pass1(cp, resultp)
  182. char *cp, *resultp;
  183. {
  184.     char c;
  185.     int col, old_col;                        /* current column no.    */
  186.     int in_cmnt = FALSE;                    /* if in a comment        */
  187.  
  188.     col = old_col = 1;
  189.  
  190.     while (c = *cp++)
  191.     {
  192.         if (docmnts && !in_cmnt && c == '/' && *cp == '*')
  193.             in_cmnt = TRUE;
  194.  
  195.         switch (c)
  196.         {
  197.             case '\t':                        /* process a tab:        */
  198.                 if (!in_cmnt)
  199.                 {                            /* if not in a comment    */
  200.                     do                        /* then add real spaces */
  201.                         *resultp++ = ' ';
  202.                     while (col++ % tabstop);
  203.                     do                        /* and log virtual ones    */
  204.                         ;
  205.                     while (old_col++ % old_tab);
  206.                 }
  207.                 else                        /* if IN a comment,        */
  208.                     do                        /* then translate as    */
  209.                         *resultp++ = ' ';    /* per the OLD tab size    */
  210.                     while (old_col++ % old_tab);
  211.                 break;
  212.  
  213.             default:                        /* handle other chars:    */
  214.                 *resultp++ = c;
  215.                 col++;                        /* just pass on through */
  216.                 old_col++;
  217.         }
  218.     }
  219.     *resultp = '\0';
  220. }
  221.  
  222. /*
  223.  * Justify comments to a common right margin.
  224.  * Complain if there isn't enough room on a line to fit the
  225.  * comment into the desired column width.
  226.  */
  227.  
  228. void pass2(line)
  229. char *line;
  230. {
  231.     char cmntbuf[MAXLINE];
  232.     char *cmnt_start, *cmnt_end;
  233.     int cmnt_len, code_len, col;
  234.  
  235.     if (!(cmnt_start = strstr(line, "/*")) ||
  236.                 !(cmnt_end = strstr(line, "*/")))
  237.         return;        /* If no complete comment, return    */
  238.  
  239.     *(cmnt_end += 2) = '\0';        /* found a comment    */
  240.     strcpy(cmntbuf, cmnt_start);    /* save the comment */
  241.     cmnt_len = strlen(cmntbuf);        /* get its length    */
  242.  
  243.     while (isspace(*--cmnt_start))    /* find last non-    */
  244.         ;                    /* space before the comment    */
  245.     *++cmnt_start = '\0';    /* and terminte the code    */
  246.  
  247.     code_len = cmnt_start - line;    /* length of code    */
  248.     if (code_len + cmnt_len > cmnt_col) /* comment fit?    */
  249.     {                                /* no. complain.    */
  250.         fprintf(stderr,
  251.             "\aWarning: comment on line %d doesn't fit.\n",
  252.             lineno);
  253.         strcat(line, cmntbuf);    /* and concatenate it    */
  254.     }
  255.     else
  256.     {            /* comment will fit. Pad with spaces:    */
  257.         for (col = code_len;
  258.                     col < (cmnt_col - cmnt_len); col++)
  259.             line[col] = ' ';
  260.         strcpy(&line[col], cmntbuf);    /* add comment    */
  261.     }
  262.     strcat(line, "\n");    
  263. }
  264.  
  265. /*
  266.  *    Create output file name by replacing extension of
  267.  *    original filename with ".lst":
  268.  */
  269.  
  270. char *makofname(dest, orig)
  271. char *dest, *orig;
  272. {
  273.     int i;
  274.     
  275.     strcpy(dest, orig);
  276.     for (i = 0; dest[i] && dest[i] != '.'; i++)
  277.         ;
  278.     strcpy(&dest[i], ".lst");
  279.     return dest;
  280. }
  281.  
  282. #if XENIX
  283. /*
  284.  * Search for first occurence of substring s2 in s1:
  285.  * Return a pointer to the first occurence, or NULL if
  286.  * none was found.
  287.  * (provided for Xenix only; this function is included
  288.  *  with most ANSI-C distribution libraries)
  289.  */
  290.  
  291. char *strstr(s1, s2)
  292. char *s1, *s2;
  293. {
  294.     int i, j, nposs;
  295.     char *p1;
  296.  
  297.     int len1 = strlen(s1);
  298.     int len2 = strlen(s2);
  299.     
  300.     if (len1 < len2)        /* can't have substring longer    */
  301.         return NULL;        /* than entire string!            */
  302.         
  303.     nposs = len1 - len2;    /* # of possible positions        */
  304.     
  305.     for (i = 0; i <= nposs; i++)
  306.     {                        /* check each possible position    */
  307.         for (j = 0, p1 = &s1[i]; j < len2;    j++)
  308.             if (*p1++ != s2[j])
  309.                 break;        /* break on 1st mismatch        */
  310.         if (j == len2)        /* if no mismatches,            */
  311.             return &s1[i];    /* then pattern was found        */
  312.     }                
  313.     return NULL;            /* didn't find the pattern        */
  314. }
  315. #endif
  316.